package fourthweek.Linked;

import fourthweek.ElementNotFoundException;
import fourthweek.UnorderedListADT;
import secondweek.EmptyCollectionException;
import secondweek.LinearNode;

public class LinkedUnorderedList<T> extends LinkedList<T> implements UnorderedListADT<T> {
    @Override
    public void addToFront(T element) {
        LinearNode<T> node = new LinearNode<T>(element);
        LinearNode<T> temp = head;
        if(isEmpty())
            head = node;
        else {
            node.setNext(head);
            while(temp.getNext() != null){
                temp = temp.getNext();
            }
            tail = temp;
            head = node;
        }
        count++;
        modCount++;
    }

    @Override
    public void addToRear(T element){
        LinearNode<T> node = new LinearNode<T>(element);
        if(isEmpty())
            head = node;
        else
            tail.setNext(node);
        tail = node;
        count++;
    }
    @Override
    public void addAfter(T element, T target) {
        LinearNode<T> node = new LinearNode<T>(element);
        LinearNode<T> temp = head;
        if(temp == null){
            head = tail = node;
        }

        while((temp != null)&&(temp.getElement() == target)){
            temp = temp.getNext();
        }

        if(temp.getNext() == null){
            temp.setNext(node);
            tail = node;
        }else{
            node.setNext(temp.getNext());
            temp.setNext(node);
        }
        count++;
        modCount++;
    }
    @Override
    public T removeFirst() {
        if (isEmpty())
            throw new EmptyCollectionException("LinkedList");

        LinearNode<T> current = head;

        if (size() == 1)
            head = tail = null;
        else
            head = current.getNext();

        count--;
        modCount++;
        return current.getElement();
    }
    @Override
    public T removeLast() {
        if (isEmpty())
            throw new EmptyCollectionException("LinkedList");
        boolean found = false;
        LinearNode<T> previous = null;
        LinearNode<T> current = head;
        while (current != null && !found) {
            if (current.equals(tail)) {
                found = true;
            } else {
                previous = current;
                current = current.getNext();
            }
        }
        if (size() == 1)
            head = tail = null;
        else {
            tail = previous;
            tail.setNext(null);
        }
        count--;
        modCount++;

        return current.getElement();
    }
    @Override
    public T remove(T targetElement) {
        if (isEmpty())
            throw new EmptyCollectionException("LinkedList");

        boolean found = false;
        LinearNode<T> previous = null;
        LinearNode<T> current = head;

        while (current != null && !found)
            if (targetElement.equals(current.getElement()))
                found = true;
            else {
                previous = current;
                current = current.getNext();
            }
        if (!found)
            throw new ElementNotFoundException("LinkedList");

        if (size() == 1)
            head = tail = null;
        else if (current.equals(head))
            head = current.getNext();
        else if (current.equals(tail))
        {
            tail = previous;
            tail.setNext(null);
        } else
            previous.setNext(current.getNext());

        count--;
        modCount++;

        return current.getElement();
    }
    @Override
    public T first() {
        if (isEmpty())
            throw new EmptyCollectionException("queue");
        else
            return head.getElement();
    }
    @Override
    public T last() {
        if (isEmpty())
            throw new EmptyCollectionException("queue");
        else
            return tail.getElement();
    }
    @Override
    public boolean contains(T target) {
        LinearNode temp = head;
        while((temp.getElement() != target)&&(temp !=  null)){
            temp = temp.getNext();
        }
        return temp.getElement() == target;
    }
    @Override
    public boolean isEmpty() {
        return count == 0;
    }
    @Override
    public int size() {
        return count;
    }
    @Override
    public String toString() {
        LinearNode<T> temp = head;
        String result = "";
        while(temp != null)
        {
            result += temp.getElement().toString() + " ";
            temp = temp.getNext();
        }
        return result;
    }
}
